import { useState, useEffect, useCallback, useRef, useContext } from "react";
import ReactFlow, {
  addEdge,
  useNodesState,
  useEdgesState,
  useOnSelectionChange,
  Background,
} from "reactflow";
import "reactflow/dist/style.css";

import { NodeBuilder, nodeTypes, exportJson } from "./nodes/Nodes";
import { NodeControl } from "./NodeEditorAddon";

import { NotifyApiContext } from "./Notify";
import { fcContext } from "./FabricCanvas";

let id = 0;
const getId = () => `nd_${id++}`;

const initialNodes = [
  NodeBuilder(getId(), "imageImport"),
  NodeBuilder(getId(), "imageDisplay", { x: 200, y: 0 }),
];

function NodeEditor() {
  const reactFlowWrapper = useRef(null);
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
  const [reactFlowInstance, setReactFlowInstance] = useState(null);

  const [selectedNodes, setSelectedNodes] = useState(null);
  const [selectedEdges, setSelectedEdges] = useState(null);

  //连线事件
  const onConnect = useCallback(
    (params) => setEdges((eds) => addEdge(params, eds)),
    []
  );

  //放置事件
  const onDragOver = useCallback((event) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = "move";
  }, []);

  const onDrop = useCallback(
    (event) => {
      event.preventDefault();

      const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
      const type = event.dataTransfer.getData("application/reactflow");

      // check if the dropped element is valid
      if (typeof type === "undefined" || !type) {
        return;
      }

      const position = reactFlowInstance.project({
        x: event.clientX - reactFlowBounds.left,
        y: event.clientY - reactFlowBounds.top,
      });

      const newNode = NodeBuilder(getId(), type, position);

      setNodes((nds) => nds.concat(newNode));
    },
    [reactFlowInstance]
  );

  //选中节点事件
  useOnSelectionChange({
    onChange: ({ nodes, edges }) => {
      setSelectedEdges(edges);
      setSelectedNodes(nodes);
    },
  });

  //删除选中节点或边
  function deleteSelection() {
    console.log("delete", selectedEdges, selectedNodes);
    reactFlowInstance.deleteElements({
      nodes: selectedNodes,
      edges: selectedEdges,
    });
  }

  function clearFlow() {
    reactFlowInstance.deleteElements({
      nodes: nodes,
      edges: edges,
    });
  }

  //导出节点
  const onSave = useCallback(() => {
    if (reactFlowInstance) {
      const flow = reactFlowInstance.toObject();
      console.log(flow);

      // 字符内容转变成blob
      const blob = new Blob([JSON.stringify(flow, null, 2)]);

      let eleLink = document.createElement("a");
      eleLink.download = "flow.json";
      eleLink.style.display = "none";
      eleLink.href = URL.createObjectURL(blob);

      // 触发点击，然后移除
      document.body.appendChild(eleLink);
      eleLink.click();
      document.body.removeChild(eleLink);
    }
  }, [reactFlowInstance]);

  // 导入节点
  const onRestore = useCallback(async () => {
    const data = await IM.json_open();
    // console.log(data)
    const flow = JSON.parse(data);

    if (flow) {
      setNodes(flow.nodes || []);
      setEdges(flow.edges || []);
    }
  }, [reactFlowInstance]);

  /**
   * 运行的逻辑
   */
  const notifyApi = useContext(NotifyApiContext);
  const fcHandler = useContext(fcContext);
  async function exportData() {
    try {
      notifyApi.loading();
      const result = await exportJson(nodes, edges);
      notifyApi.destroy();

      // console.log("result:", result);
      //处理结果
      let fcPos = 0;
      for (let i = 0; i < result.length; i++) {
        if (result[i].type === "imageShow") {
          //图片显示节点，添加图片
          fcHandler.addImage(result[i].data.path, fcPos, fcPos);
          fcPos += 40;
        }
      }
    } catch (e) {
      notifyApi.destroy();
      notifyApi.error(e);
    }
  }

  return (
    <div
      className="reactflow-wrapper"
      ref={reactFlowWrapper}
      style={{ width: "100%", height: "100%" }}
    >
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        onInit={setReactFlowInstance}
        onDrop={onDrop}
        onDragOver={onDragOver}
        nodeTypes={nodeTypes}
        snapToGrid={true}
        fitView
      >
        <NodeControl
          deleteSelection={deleteSelection}
          exportData={exportData}
          onSave={onSave}
          onRestore={onRestore}
          clearFlow={clearFlow}
        />
        <Background style={{ backgroundColor: "#f7f7f8" }} />
      </ReactFlow>
    </div>
  );
}

export default NodeEditor;
